/* Activation from a native component. The data inside one of these components
 * consists of a tar.gz file containing an archive of the source code for the
 * component, probably in written in C.
 *
 * Kew initiates an autotools build of the component, and caches the built module
 * which is then used as the basis for activation.
 *
 * WARNING!
 * Even initiating the build requires that you absolutely trust the code to be
 * activated, as it has the full effective permissions of the user from the
 * point that configure is called in the unpacked archive.
 *
 * If this is no good, you should replace the native activator with a block
 * that brings execution straight back to trusted code.
 *
 * Build process is invoked with $(ComponentSpecificTempDir)/configure
 * --prefix=$(UserHomeDir)/kew/components/native/$(ComponentDigest)
 * --kew-native-component-cache-install (signals it is being built by Kew native activator)
 * Followed by make install
 *
 * It is possible to be more responsive by running over archive files in advance and
 * triggering a background build into the cache. In fact, if we have a privileged builder
 * process it can install compiled versions directly into system-level cache to be shared
 * by all users.
 */

g_get_home_dir()
g_get_tmp_dir()
gboolean g_spawn_command_line_sync  (const gchar          *command_line,
                                     gchar               **standard_output,
                                     gchar               **standard_error,
                                     gint                 *exit_status,
                                     GError              **error);

char *kew_digest_string_md5(char *data, guint length)
{
    int i;
    char *result = g_new(char, 33);
    
    md5_state_t state;
    md5_byte_t digest[16];

    md5_init(&state);
    md5_append(&state, data, length);
    md5_finish(&state, digest);
    
    for (i = 0; i < 16; ++i) {
        sprintf(&result[i], "%x", digest[i]);
    }
    result[32] = '\0';
    return result;    
}

KEW_METHOD(activate) /* :NativeComponent :ActivationArgs... ^ActivationResults... */
{
    /* For native components, the activation_cache field holds the activation block the register
     * function returned from the module. */

/* FIXME: this doesn't cope with the activation block being called with different container values!
 * Maybe the registration phase needs to be split into selector/call shape registration, and
 * later type registration (which could include the call to the activation block)
 *
 * kew_native_component_bind(vm); // registers call shapes and selectors
 * activated_component = kew_native_component_activate(env, container, services);
 * // registers types and returns block or object
 * // finally, call activated block or object
 *
 * also need to check type of argument. can this be elided by placing in Component itself?
 * although the only reason we need it is to allow activation caching.
 *
 * Components need to hold a list of signatures that are checked by the activator prior to
 * starting the search for an activation block. Signatures need to be computed across MIME
 * type and component contents. Should they be computed across subcomponents as well?
 * I think so.
 * Actually this should be the job of the loader so that untrusted data is not even loaded
 * in the first place.
 *
 * FIXME: we also need to somehow support system native components - ones that are precompiled
 * and supplied with Kew itself, and that will usually form the basis for services.
 */
    if (! imp->activation_cache) {
        void *register_func;
        char *component_digest = kew_digest_string_md5(imp->data, imp->length);
        char *home_dir = g_get_home_dir(); /* statically allocated */
        char *native_cache = "/kew/cache/components/native/";
    
        char *component_filename = g_strconcat(home_dir, native_cache, component_digest, "/lib/component.la", NULL);
        g_free(component_digest);
        
        lt_dlhandle component_handle = lt_dlopen(component_filename);
        g_free(component_filename);
        
        /* FIXME: need to check for a compiled native module cache "miss" here and trigger a rebuild */
        
        register_func = lt_dlsym(component_handle, "kew_native_component_register");
        imp->activation_cache = (*register_func)(vm, imp->container);
    }

    kew_send(imp->activation_cache, kew_sel_call, kew_shape_M_M, args, results);
}

static void build_native_component()
{
    char *temp_dir = g_get_tmp_dir(); /* statically allocated */
    char *user_id = g_get_user_name();
    char *component_digest = kew_md5_digest(imp->data, imp->length);
}
